import { PrismaClient, WithdrawStatus, WithdrawType, UserTier } from '@prisma/client'

interface CliOptions {
  userIds: number[] | null
  idNumbers: string[] | null
  all: boolean
  verbose: boolean
}

interface BalanceInsight {
  userId: number
  idNumber: string
  name: string
  tier: UserTier
  depositTotal: number
  rewardTotalKrw: number
  rewardTotalNear: number
  rewardRecordsNear: number
  withdrawBalanceTotal: number
  withdrawRewardTotal: number
  currentBalance: number
  currentTotal: number
  currentFrozen: number
  stakingTotalRewardsNear: number
  expectedBalance: number
  balanceDiff: number
  rewardNearDiff: number
  hasAnomaly: boolean
  anomalyReasons: string[]
  counts: {
    deposits: number
    withdrawBalance: number
    withdrawReward: number
    settlements: number
    rewards: number
  }
}

const prisma = new PrismaClient()

const parseArgs = (): CliOptions => {
  const options: CliOptions = {
    userIds: null,
    idNumbers: null,
    all: false,
    verbose: false
  }

  for (const arg of process.argv.slice(2)) {
    if (arg === '--all') {
      options.all = true
    } else if (arg === '--verbose') {
      options.verbose = true
    } else if (arg.startsWith('--userId=')) {
      const ids = arg
        .replace('--userId=', '')
        .split(',')
        .map(item => Number(item.trim()))
        .filter(id => !Number.isNaN(id))
      if (ids.length === 0) {
        throw new Error('无效的 --userId 参数，至少提供一个数字ID')
      }
      options.userIds = ids
    } else if (arg.startsWith('--idNumber=')) {
      const idNumbers = arg
        .replace('--idNumber=', '')
        .split(',')
        .map(item => item.trim())
        .filter(item => item.length > 0)
      if (idNumbers.length === 0) {
        throw new Error('无效的 --idNumber 参数，至少提供一个身份证号')
      }
      options.idNumbers = idNumbers
    } else {
      throw new Error(`未知参数: ${arg}`)
    }
  }

  if (!options.all && !options.userIds && !options.idNumbers) {
    throw new Error('请通过 --userId, --idNumber 或 --all 指定检查范围')
  }

  return options
}

const formatDecimal = (value: unknown): number => {
  if (value === null || value === undefined) {
    return 0
  }
  if (typeof value === 'number') {
    return value
  }
  if (typeof value === 'bigint') {
    return Number(value)
  }
  if (typeof value === 'object') {
    const decimalLike = value as { toNumber?: () => number }
    if (typeof decimalLike.toNumber === 'function') {
      return decimalLike.toNumber()
    }
  }
  return Number(value)
}

const roundKrw = (value: number): number => Math.round(value * 100) / 100
const roundNear = (value: number): number => Math.round(value * 10000) / 10000

const resolveTargetUserIds = async (options: CliOptions): Promise<number[]> => {
  const userIdSet = new Set<number>()

  if (options.userIds) {
    options.userIds.forEach(id => userIdSet.add(id))
  }

  if (options.idNumbers) {
    const foundUsers = await prisma.user.findMany({
      where: { idNumber: { in: options.idNumbers } },
      select: { id: true, idNumber: true }
    })

    const mapByIdNumber = new Map<string, number>()
    foundUsers.forEach(user => mapByIdNumber.set(user.idNumber, user.id))

    for (const idNumber of options.idNumbers) {
      const resolvedId = mapByIdNumber.get(idNumber)
      if (resolvedId) {
        userIdSet.add(resolvedId)
      } else {
        console.warn(`⚠️ 身份证号 ${idNumber} 未找到对应用户，已跳过`)
      }
    }
  }

  if (options.all || userIdSet.size === 0) {
    const stakingUsers = await prisma.userStaking.findMany({
      where: {
        OR: [
          { stakedAmount: { gt: 0 } },
          { totalRewardsNear: { gt: 0 } }
        ]
      },
      select: { userId: true }
    })
    stakingUsers.forEach(item => userIdSet.add(item.userId))
  }

  return Array.from(userIdSet)
}

const analyzeSingleUser = async (userId: number): Promise<BalanceInsight | null> => {
  const user = await prisma.user.findUnique({
    where: { id: userId },
    select: {
      idNumber: true,
      name: true,
      tier: true
    }
  })

  if (!user) {
    console.warn(`用户 ${userId} 不存在，已跳过`)
    return null
  }

  const balance = await prisma.userBalance.findUnique({
    where: { userId },
    select: {
      balance: true,
      frozen: true,
      total: true
    }
  })

  const staking = await prisma.userStaking.findUnique({
    where: { userId },
    select: {
      totalRewardsNear: true
    }
  })

  const depositSummary = await prisma.depositRecord.aggregate({
    where: {
      userId,
      status: 'CONFIRMED'
    },
    _sum: { amount: true },
    _count: { amount: true }
  })

  const withdrawBalanceSummary = await prisma.withdrawRecord.aggregate({
    where: {
      userId,
      status: WithdrawStatus.CONFIRMED,
      withdrawType: WithdrawType.BALANCE
    },
    _sum: { amount: true },
    _count: { amount: true }
  })

  const withdrawRewardSummary = await prisma.withdrawRecord.aggregate({
    where: {
      userId,
      status: WithdrawStatus.CONFIRMED,
      withdrawType: WithdrawType.STAKING_REWARD
    },
    _sum: { amount: true },
    _count: { amount: true }
  })

  const settlementSummary = await prisma.stakingSettlement.aggregate({
    where: { userId },
    _sum: {
      rewardKrw: true,
      rewardNear: true
    },
    _count: { id: true }
  })

  const rewardSummary = await prisma.stakingReward.aggregate({
    where: { userId },
    _sum: {
      amount: true
    },
    _count: { id: true }
  })

  const depositTotal = roundKrw(formatDecimal(depositSummary._sum.amount))
  const rewardTotalKrw = roundKrw(formatDecimal(settlementSummary._sum.rewardKrw))
  const rewardTotalNear = roundNear(formatDecimal(settlementSummary._sum.rewardNear))
  const rewardRecordsNear = roundNear(formatDecimal(rewardSummary._sum.amount))
  const withdrawBalanceTotal = roundKrw(formatDecimal(withdrawBalanceSummary._sum.amount))
  const withdrawRewardTotal = roundKrw(formatDecimal(withdrawRewardSummary._sum.amount))

  const currentBalance = balance ? roundKrw(formatDecimal(balance.balance)) : 0
  const currentFrozen = balance ? roundKrw(formatDecimal(balance.frozen)) : 0
  const currentTotal = balance ? roundKrw(formatDecimal(balance.total)) : 0
  const stakingTotalRewardsNear = staking ? roundNear(formatDecimal(staking.totalRewardsNear)) : 0

  const expectedBalance = roundKrw(depositTotal + rewardTotalKrw - withdrawBalanceTotal)
  const balanceDiff = roundKrw(currentBalance - expectedBalance)
  const rewardNearDiff = roundNear(rewardRecordsNear - rewardTotalNear)

  const anomalyReasons: string[] = []
  if (Math.abs(balanceDiff) > 1) {
    anomalyReasons.push(`可用余额与理论值差异 ${balanceDiff.toFixed(2)} KRW`)
  }
  if (Math.abs(rewardNearDiff) > 0.0001) {
    anomalyReasons.push(`奖励流水NEAR与结算NEAR差异 ${rewardNearDiff.toFixed(4)} NEAR`)
  }
  if (Math.abs(stakingTotalRewardsNear - rewardTotalNear) > 0.0001) {
    anomalyReasons.push(`user_staking.totalRewardsNear 与结算NEAR不一致，差值 ${(stakingTotalRewardsNear - rewardTotalNear).toFixed(4)} NEAR`)
  }
  if (depositTotal === 0 && currentBalance > 0) {
    anomalyReasons.push('未找到充值记录但可用余额大于0')
  }

  return {
    userId,
    idNumber: user.idNumber,
    name: user.name,
    tier: user.tier,
    depositTotal,
    rewardTotalKrw,
    rewardTotalNear,
    rewardRecordsNear,
    withdrawBalanceTotal,
    withdrawRewardTotal,
    currentBalance,
    currentTotal,
    currentFrozen,
    stakingTotalRewardsNear,
    expectedBalance,
    balanceDiff,
    rewardNearDiff,
    hasAnomaly: anomalyReasons.length > 0,
    anomalyReasons,
    counts: {
      deposits: depositSummary._count.amount ?? 0,
      withdrawBalance: withdrawBalanceSummary._count.amount ?? 0,
      withdrawReward: withdrawRewardSummary._count.amount ?? 0,
      settlements: settlementSummary._count.id ?? 0,
      rewards: rewardSummary._count.id ?? 0
    }
  }
}

const main = async (): Promise<void> => {
  const options = parseArgs()
  const userIds = await resolveTargetUserIds(options)

  if (userIds.length === 0) {
    console.log('没有需要检查的用户。')
    return
  }

  const insights: BalanceInsight[] = []

  for (const userId of userIds) {
    try {
      const insight = await analyzeSingleUser(userId)
      if (insight) {
        insights.push(insight)
        if (options.verbose) {
          console.log(JSON.stringify(insight, null, 2))
        }
      }
    } catch (error) {
      console.error(`分析用户 ${userId} 失败:`, error)
    }
  }

  const summary = {
    checkedUsers: insights.length,
    anomalyUsers: insights.filter(item => item.hasAnomaly).length,
    results: insights.map(item => ({
      userId: item.userId,
      idNumber: item.idNumber,
      name: item.name,
      tier: item.tier,
      depositTotal: item.depositTotal,
      rewardTotalKrw: item.rewardTotalKrw,
      rewardTotalNear: item.rewardTotalNear,
      withdrawBalanceTotal: item.withdrawBalanceTotal,
      withdrawRewardTotal: item.withdrawRewardTotal,
      currentBalance: item.currentBalance,
      expectedBalance: item.expectedBalance,
      balanceDiff: item.balanceDiff,
      currentFrozen: item.currentFrozen,
      stakingTotalRewardsNear: item.stakingTotalRewardsNear,
      rewardRecordsNear: item.rewardRecordsNear,
      rewardNearDiff: item.rewardNearDiff,
      hasAnomaly: item.hasAnomaly,
      anomalyReasons: item.anomalyReasons,
      counts: item.counts
    }))
  }

  console.log(JSON.stringify(summary, null, 2))
}

main().catch(async error => {
  console.error('资金巡检脚本执行失败:', error)
  await prisma.$disconnect()
  process.exit(1)
}).finally(async () => {
  await prisma.$disconnect()
})
